package com.example.kotlinExample.controller

import cn.hutool.poi.excel.ExcelUtil
import com.example.kotlinExample.annotation.OperLog
import com.example.kotlinExample.entity.PageResult
import com.example.kotlinExample.entity.Person
import com.example.kotlinExample.entity.PersonParam
import com.example.kotlinExample.enum.Gender
import com.example.kotlinExample.exception.ApiException
import com.example.kotlinExample.properties.MyProperties
import com.example.kotlinExample.service.UserSignService
import com.example.kotlinExample.socket.WebSocket
import com.google.gson.GsonBuilder
import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.data.redis.core.RedisTemplate
import org.springframework.validation.annotation.Validated
import org.springframework.web.bind.annotation.*
import org.springframework.web.client.RestTemplate
import org.springframework.web.multipart.MultipartFile
import java.io.File
import java.io.FileOutputStream
import java.lang.reflect.Type
import java.net.HttpURLConnection
import java.net.URL
import java.time.LocalDate
import java.util.*
import javax.imageio.ImageIO
import javax.validation.Valid

/**
 * 用户接口
 */
@RestController
class PersonController {

    val logger: Logger = LoggerFactory.getLogger(this::class.java)


    @Autowired
    private lateinit var restTemplate: RestTemplate

    @Autowired
    lateinit var myProperties: MyProperties

    @Autowired
    lateinit var redisTemplate: RedisTemplate<Any, Any>

    @Autowired
    lateinit var userSignService: UserSignService


    @GetMapping("/online")
    fun getOnlineUserNumber(): Int {
        WebSocket.webSocketSet["王大锤"]?.onMessage("{\"name\":\"a\",\"toName\":\"王大锤\",\"message\":\"王大锤,你好啊\"}")
        return WebSocket.webSocketSet.size
    }

    @GetMapping("getList")
    fun getList(ids: Array<String>): Array<String> {
        return ids
    }

    @GetMapping("/pdf/{page}")
    fun getPdf(@PathVariable page: Int): String? {
        val forObject = restTemplate.getForObject(
            "https://anime-pictures.net/pictures/view_posts/$page?lang=jp&aspect=16:9&type=json&posts_per_page=50",
            PageResult::class.java
        )
//        val forObject = restTemplate.getForObject("https://konachan.net/post.json?limit=1000&page=$page", Array<KonPhoto>::class.java)
        forObject?.posts?.forEach {
            val filename = "${it.md5}${it.ext}"
            val imageUrl = "https://images.anime-pictures.net/${it.md5.subSequence(0, 3)}/$filename"
//            val filename = it.jpeg_url.substring(it.jpeg_url.lastIndexOf("/"))
            GlobalScope.launch(Dispatchers.IO) {
                download(imageUrl, filename, "D:/壁纸/file")
            }
        }
        println("执行其他")
        return "runBlocking"
    }

    suspend fun download(urlString: String, filename: String, savePath: String) {
        // 构造URL
        val url = URL(urlString)
        // 打开连接
        val con = url.openConnection() as HttpURLConnection
        //设置请求超时为5s
        con.connectTimeout = 5000
        // 输入流
        val inputStream = con.inputStream
        val read = ImageIO.read(inputStream)

        // 输出的文件流
        val sf = File(savePath)
        if (!sf.exists()) {
            sf.mkdirs()
        }
        val os = FileOutputStream(sf.path + "\\" + filename)
        val write = ImageIO.write(read, "png", os)
        if (write) logger.info("下载成功..") else logger.info("下载失败")
        // 完毕，关闭所有链接
        os.close()
        inputStream.close()
    }

    @GetMapping("/user/{username}")
    fun getUser(@PathVariable username: String) = username

    @PostMapping("/person")
    fun modifyPerson(@Valid @RequestBody person: Person) = person

    @GetMapping("/person/personal")
    fun getGender() = Gender.getCodeByGender(Gender.MAN.gender)

    /**
     * 图片上传
     * [images] 图片数组
     */
    @PostMapping("/uploadImage")
    fun uploadImage(images: Array<MultipartFile>): String {
        for (image in images) {
            println("图片名称: " + image.originalFilename)
            println("图片大小: " + String.format("%.2f", (image.size / 1024.0)) + "kb")
            val buffer = ImageIO.read(image.inputStream) ?: throw ApiException("${image.originalFilename},不是一张图片")
            println("图片尺寸: " + buffer.width + "x" + buffer.height)
        }
        return images.toString()
    }

    /**
     * 修改用户信息
     */
    @PostMapping("/modify/person")
    fun modifyPerson(@Validated personParam: PersonParam): String {
        return "sss"
    }

    @PostMapping("/message/read")
    fun messageRead(): Boolean {
        redisTemplate.opsForSet().add("message:read:userId:messageId", 3)
        redisTemplate.opsForSet().add("message:read:userId:messageId", 4)
        redisTemplate.opsForSet().add("message:read:userId:messageId", 5)
        return true
    }

    @GetMapping("/message/get")
    fun getMessageRead(): Any? {
        return redisTemplate.opsForSet().members("message:read:userId:messageId")
    }

    @PostMapping("/person/importPersonalInfo")
    fun readerExcel(file: MultipartFile): String {
        var reader = ExcelUtil.getReader(file.inputStream)
        val sheetNames = reader.sheetNames
        for (sheetName in sheetNames) {
            reader = ExcelUtil.getReader(file.inputStream, sheetName)
            reader.isIgnoreEmptyRow = false
            val readAll = reader.read(0)
            for (mutableList in readAll) {
                println(mutableList)
            }
        }

        return reader.read().toString()
    }

    /**
     * 测试从application.yml为对象赋值
     * @return mypropertis
     */
    @GetMapping("/properties")
    @OperLog(operModul = "配置", operType = "", operDesc = "获取配置信息")
    fun properties(): MyProperties {
        val day = LocalDate.now().dayOfMonth

        redisTemplate.opsForList().leftPushAll("person", Person("王大锤", 29, Date()), Person("李天明", 29, Date()))
        redisTemplate.opsForList().rightPop("person")?.let {
            val gson = GsonBuilder().registerTypeAdapter(Date::class.java, object : JsonDeserializer<Date> {
                override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext?): Date {
                    return Date(json.asJsonPrimitive.asLong)
                }
            }).create()
            val person = gson.fromJson(it.toString(), Person::class.java)
            println(person)
            person
        }

        redisTemplate.opsForValue().multiGet(listOf("12", "123"))
//        redisTemplate.expire("person", 1, TimeUnit.MINUTES)

//        redisTemplate.opsForValue().setBit("signIn:userId:1", 11, true)
//        redisTemplate.execute {
//            it.bitCount("signIn:userId:1".toByteArray())?.let { count ->
//                println(count)
//            }
//        }

//        redisTemplate.opsForValue().apply {
//            set(String.format(TOKEN_PREFIX, 1234), Person("王大锤", 26), 1, TimeUnit.MINUTES)
//            set(String.format(TOKEN_PREFIX, "abcd"), "abcd", 1, TimeUnit.MINUTES)
//        }
//        redisTemplate.opsForHash<String,Any>().apply {
//            put("users", "1", Person("王大锤", 26))
//            put("users", "2", Person("李天明", 27))
//            put("users", "3", Person("张三丰", 27))
//            put("users", "4", Person("四海维嘉", 27))
//            put("users", "5", Person("五张柳府", 27))
//        }

        redisTemplate.opsForValue().getBit("signIn:userId:1", day.toLong())?.let {
            if (it) {
                throw ApiException("今天已经签到过了")
            } else {
                redisTemplate.opsForValue().setBit("signIn:userId:1", day.toLong(), true)
            }
        }

        return myProperties
    }

    /**
     * 签到
     */
    @PostMapping("sign")
    fun doSign() = userSignService.doSign(1, LocalDate.now())

    /**
     * 是否签到
     */
    @GetMapping("sign")
    fun checkSign() = userSignService.checkSign(1, LocalDate.now())

    /**
     * 签到次数
     */
    @GetMapping("getSignCount")
    fun getSignCount() = userSignService.getSignCount(1, LocalDate.now())

    /**
     * 获取当月连续签到次数
     */
    @GetMapping("/getContinuousSignCount")
    fun getContinuousSignCount() = userSignService.getContinuousSignCount(1, LocalDate.now())

    /**
     * 当月首次签到日期
     */
    @GetMapping("/getFirstSignDate")
    fun getFirstSignDate() = userSignService.getFirstSignDate(1, LocalDate.now())

    /**
     * 当月签到信息
     */
    @GetMapping("/getSignInfo")
    fun getSignInfo() = userSignService.getSignInfo(1, LocalDate.now())

    companion object {
        const val TOKEN_PREFIX = "token:%s"
    }

}